{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "conv = torch.nn.Conv2d(\n",
    "    in_channels=3,  # RGB\n",
    "    out_channels=8,  # 8 个卷积核\n",
    "    kernel_size=3,\n",
    "    stride=1,\n",
    "    padding=1,\n",
    "    bias=False,\n",
    ")  # 先不考虑偏置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Conv2d(3, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n"
     ]
    }
   ],
   "source": [
    "print(conv) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([8, 3, 3, 3])\n"
     ]
    }
   ],
   "source": [
    "print(conv.weight.shape)  # 必须是 [8, 3, 3, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "72\n"
     ]
    }
   ],
   "source": [
    "print(torch.arange(1, 73).numel())  # 必须是 72"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(0.0102, grad_fn=<MeanBackward0>) tensor(0.1174, grad_fn=<StdBackward0>)\n"
     ]
    }
   ],
   "source": [
    "# 查看初始化的卷积核权重 Kaiming 分布\n",
    "print(conv.weight.mean(), conv.weight.std())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 手动指定初始化权重大小（替代Kaiming）\n",
    "torch.nn.init.constant_(conv.weight, 1.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "RuntimeError",
     "evalue": "shape '[8, 3, 3, 3]' is invalid for input of size 72",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
      "\u001b[1;32m/root/MyCode/digital-handwriting-recognition/experiment/CNN.ipynb Cell 8\u001b[0m line \u001b[0;36m2\n\u001b[1;32m      <a href='vscode-notebook-cell://localhost:8080/root/MyCode/digital-handwriting-recognition/experiment/CNN.ipynb#W4sdnNjb2RlLXJlbW90ZQ%3D%3D?line=0'>1</a>\u001b[0m \u001b[39m# 修改已经实例化的层次对象权重\u001b[39;00m\n\u001b[0;32m----> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/digital-handwriting-recognition/experiment/CNN.ipynb#W4sdnNjb2RlLXJlbW90ZQ%3D%3D?line=1'>2</a>\u001b[0m conv\u001b[39m.\u001b[39mweight\u001b[39m.\u001b[39mdata \u001b[39m=\u001b[39m torch\u001b[39m.\u001b[39;49marange(\u001b[39m1\u001b[39;49m, \u001b[39m73\u001b[39;49m)\u001b[39m.\u001b[39;49mreshape(\u001b[39m8\u001b[39;49m, \u001b[39m3\u001b[39;49m, \u001b[39m3\u001b[39;49m, \u001b[39m3\u001b[39;49m)\u001b[39m.\u001b[39mfloat()\n",
      "\u001b[0;31mRuntimeError\u001b[0m: shape '[8, 3, 3, 3]' is invalid for input of size 72"
     ]
    }
   ],
   "source": [
    "# 修改已经实例化的层次对象权重\n",
    "conv.weight.data = torch.arange(1, 73).reshape(8, 3, 3, 3).float()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里之所以是错误的是因为27并不是权重的正确的数量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 修改已经实例化的层次对象权重\n",
    "conv.weight.data = torch.arange(1, 217).reshape(8, 3, 3, 3).float()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([8, 3, 3, 3])\n",
      "tensor([ 1., 10., 19.], grad_fn=<SelectBackward0>)\n"
     ]
    }
   ],
   "source": [
    "# 观察新的权重\n",
    "print(conv.weight.shape)   # torch.Size([8, 3, 3, 3])\n",
    "print(conv.weight[0, :, 0, 0])  # 第 0 个核在 3 个通道的左上角的 3 个权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Mock 一个随机的Image形式数据\n",
    "x = torch.ones(1, 3, 1, 1)   # batch=1, RGB=3, H=W=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(42., grad_fn=<SelectBackward0>)\n"
     ]
    }
   ],
   "source": [
    "out = conv(x)\n",
    "print(out[0, 0, 0, 0])   # tensor(99., grad_fn=<SelectBackward0>)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "science39",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
